home *** CD-ROM | disk | FTP | other *** search
- {*********************************************************}
- {* AADES *}
- {* Copyright (c) Julian M Bucknall 2000 *}
- {* All rights reserved. *}
- {*********************************************************}
- {* Algorithms Alfresco: DES encryption/decryption *}
- {*********************************************************}
-
- {Note: this unit is released as freeware. In other words, you are free
- to use this unit in your own applications, however I retain all
- copyright to the code. JMB}
-
- unit AADES;
-
- interface
-
- uses
- SysUtils,
- Classes;
-
- type
- TaaDesKey64 = array [0..7] of byte;
- {type for a DES key}
- TaaDesBlock = array [0..7] of byte;
- {type for a DES data block}
-
- TaaDesMode = ( {Different DES modes...}
- dmECB, {..ECB (Electronic Code Book)}
- dmCBC); {..CBC (Cipher Block Chaining)}
-
- type
- TaaDesEngine = class
- private
- FState : pointer;
- FKey : TaaDesKey64;
- FEncrypting : boolean;
- protected
- public
- constructor Create(const aKey : TaaDesKey64;
- aToEncrypt : boolean);
- destructor Destroy; override;
-
- procedure ProcessBlock(const aSrc : TaaDesBlock;
- var aDest: TaaDesBlock);
- procedure ProcessStream(aInStream : TStream;
- aOutStream : TStream;
- aMode : TaaDesMode);
-
- property Encrypting : boolean read FEncrypting;
- end;
-
-
- implementation
-
- type
- T32bits = array [0..3] of byte;
- T48bits = array [0..5] of byte;
- TDesKeyArray = array [0..55] of boolean;
- TSubKey = T48bits;
- PSubKeyArray = ^TSubKeyArray;
- TSubKeyArray = array [1..16] of TSubKey;
-
- const
- BitMask : array [0..7] of byte =
- ($80, $40, $20, $10, $08, $04, $02, $01);
-
- const
- DesKeyBitSelection : array [0..55] of byte =
- (56, 48, 40, 32, 24, 16, 8, 0,
- 57, 49, 41, 33, 25, 17, 9, 1,
- 58, 50, 42, 34, 26, 18, 10, 2,
- 59, 51, 43, 35, 62, 54, 46, 38,
- 30, 22, 14, 6, 61, 53, 45, 37,
- 29, 21, 13, 5, 60, 52, 44, 36,
- 28, 20, 12, 4, 27, 19, 11, 3);
-
- DesSubKeyShifts : array [1..16] of byte =
- (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1);
-
- DesSubKeyPerm : array [0..47] of byte =
- (13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3,
- 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39,
- 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31);
-
- DesStartPerm : array [0..63] of byte =
- (57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
- 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
- 56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2,
- 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6);
-
- DesFinalPerm : array [0..63] of byte =
- (39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30,
- 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28,
- 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26,
- 33, 1, 41, 9, 49, 17, 57, 25, 32, 0, 40, 8, 48, 16, 56, 24);
-
- DesEBoxPerm : array [0..47] of byte =
- (31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8,
- 7, 8, 9, 10, 11, 12, 11, 12, 13, 14, 15, 16,
- 15, 16, 17, 18, 19, 20, 19, 20, 21, 22, 23, 24,
- 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0);
-
- DesSBox1 : array [0..63] of byte =
- (14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
- 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
- 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
- 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13);
-
- DesSBox2 : array [0..63] of byte =
- (15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
- 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
- 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
- 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9);
-
- DesSBox3 : array [0..63] of byte =
- (10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
- 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
- 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
- 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12);
-
- DesSBox4 : array [0..63] of byte =
- ( 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
- 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
- 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
- 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14);
-
- DesSBox5 : array [0..63] of byte =
- ( 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
- 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
- 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
- 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3);
-
- DesSBox6 : array [0..63] of byte =
- (12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
- 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
- 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
- 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13);
-
- DesSBox7 : array [0..63] of byte =
- ( 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
- 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
- 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
- 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12);
-
- DesSBox8 : array [0..63] of byte =
- (13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
- 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
- 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
- 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11);
-
- DesPBoxPerm : array [0..31] of byte =
- (15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9,
- 1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24);
-
-
- {===Helper routines==================================================}
- procedure CalcPermutation(const aSource;
- var aDest;
- const aMapping;
- aMapCount : integer);
- var
- Src : TByteArray absolute aSource;
- Dest : TByteArray absolute aDest;
- Map : TByteArray absolute aMapping;
- i : integer;
- FromByte : integer;
- FromBit : integer;
- ToByte : integer;
- Accum : byte;
- CurBit : byte;
- begin
- {using the mapping, transfer bits from source to destination}
- ToByte := 0;
- Accum := 0;
- CurBit := $80;
- for i := 0 to pred(aMapCount) do begin
- FromByte := Map[i] div 8;
- FromBit := Map[i] mod 8;
- if ((Src[FromByte] and BitMask[FromBit]) <> 0) then
- Accum := Accum or CurBit;
- CurBit := CurBit shr 1;
- if (CurBit = 0) then begin
- Dest[ToByte] := Accum;
- inc(ToByte);
- Accum := 0;
- CurBit := $80;
- end;
- end;
- end;
- {--------}
- procedure CalcSubKeys(const aKey56 : TDesKeyArray;
- var aSubKeys : TSubKeyArray;
- aForEncrypt : boolean);
- var
- i : integer;
- LeftInx : integer;
- ToInx : integer;
- Round : integer;
- Temp56 : TDesKeyArray;
- SubKey : TSubKey;
- ToByte : integer;
- Accum : byte;
- CurBit : byte;
- TotalRotation : integer;
- begin
- {calculate the subkeys for all 16 rounds...}
- for Round := 1 to 16 do begin
- {calculate the total rotation required for this round}
- TotalRotation := 0;
- for i := 1 to Round do
- inc(TotalRotation, DesSubKeyShifts[i]);
- {left rotate the two halves of the 56-bit key by the
- required shift for this round}
- for LeftInx := 0 to 27 do begin
- {calculate the next destination index}
- ToInx := LeftInx - TotalRotation;
- if (ToInx < 0) then {we have wrapped}
- inc(ToInx, 28);
- {move the bit from the original key to our temp key,
- first for the left half and then for the right half}
- Temp56[ToInx] := aKey56[LeftInx];
- Temp56[ToInx+28] := aKey56[LeftInx+28];
- end;
- {now calculate this round's subkey by selecting the correct bits}
- ToByte := 0;
- Accum := 0;
- CurBit := $80;
- for i := 0 to 47 do begin
- if Temp56[DesSubKeyPerm[i]] then
- Accum := Accum or CurBit;
- CurBit := CurBit shr 1;
- if (CurBit = 0) then begin
- SubKey[ToByte] := Accum;
- inc(ToByte);
- Accum := 0;
- CurBit := $80;
- end;
- end;
- {save the subkey
- note: for decryption we save subkeys in reverse order}
- if aForEncrypt then
- aSubKeys[Round] := SubKey
- else
- aSubKeys[17-Round] := SubKey;
- end;
- end;
- {--------}
- procedure ConvertDesKey(const aDesKey64 : TaaDesKey64;
- var aKey56 : TDesKeyArray);
- var
- i : integer;
- ByteNum : integer;
- BitNum : integer;
- begin
- {for each outbit bit...}
- for i := 0 to 55 do begin
- {work out which byte in the input key and which bit within
- that byte that the output bit will be found}
- ByteNum := DesKeyBitSelection[i] div 8;
- BitNum := DesKeyBitSelection[i] mod 8;
- {set the output boolean equal to this bit}
- aKey56[i] := (aDesKey64[ByteNum] and BitMask[BitNum]) <> 0;
- end;
- end;
- {--------}
- function F(const aRight : longint; const aSubKey : TSubKey) : longint;
- var
- i : integer;
- BigRight : T48Bits;
- Accum : byte;
- Temp32 : T32Bits;
- begin
- {start off with the expansion permutation: the E-Box}
- CalcPermutation(aRight, BigRight, DesEBoxPerm, sizeof(DesEBoxPerm));
-
- {XOR the subkey into the expanded data}
- for i := 0 to 5 do
- BigRight[i] := BigRight[i] xor aSubKey[i];
-
- {now wade into the S-Boxes}
- {..first}
- Accum := (BigRight[0] and $FC) shr 2;
- Temp32[0] := DesSBox1[Accum] shl 4;
- {..second}
- Accum := ((BigRight[0] and $03) shl 4) or
- ((BigRight[1] and $F0) shr 4);
- Temp32[0] := Temp32[0] or DesSBox2[Accum];
- {..third}
- Accum := ((BigRight[1] and $0F) shl 2) or
- ((BigRight[2] and $C0) shr 6);
- Temp32[1] := DesSBox3[Accum] shl 4;
- {..fourth}
- Accum := (BigRight[2] and $3F);
- Temp32[1] := Temp32[1] or DesSBox4[Accum];
- {..fifth}
- Accum := (BigRight[3] and $FC) shr 2;
- Temp32[2] := DesSBox5[Accum] shl 4;
- {..sixth}
- Accum := ((BigRight[3] and $03) shl 4) or
- ((BigRight[4] and $F0) shr 4);
- Temp32[2] := Temp32[2] or DesSBox6[Accum];
- {..seventh}
- Accum := ((BigRight[4] and $0F) shl 2) or
- ((BigRight[5] and $C0) shr 6);
- Temp32[3] := DesSBox7[Accum] shl 4;
- {..eighth}
- Accum := (BigRight[5] and $3F);
- Temp32[3] := Temp32[3] or DesSBox8[Accum];
-
- {end up with the final permutation: the P-Box}
- CalcPermutation(Temp32, Result, DesPBoxPerm, sizeof(DesPBoxPerm));
- end;
- {--------}
- procedure XorDesBlock(const aSource : TaaDesBlock;
- var aDest : TaaDesBlock);
- var
- i : integer;
- begin
- for i := 0 to pred(sizeof(TaaDesBlock)) do
- aDest[i] := aDest[i] xor aSource[i];
- end;
- {====================================================================}
-
-
- {===TaaDesEngine=====================================================}
- constructor TaaDesEngine.Create(const aKey : TaaDesKey64;
- aToEncrypt : boolean);
- var
- Temp56 : TDesKeyArray;
- begin
- inherited Create;
- {save parameters}
- FKey := aKey;
- FEncrypting := aToEncrypt;
- {allocate the subkey array}
- FState := AllocMem(sizeof(TSubKeyArray));
- {convert the DES key and create the subkeys}
- ConvertDesKey(FKey, Temp56);
- CalcSubKeys(Temp56, PSubKeyArray(FState)^, Encrypting);
- end;
- {--------}
- destructor TaaDesEngine.Destroy;
- begin
- {free the subkey array}
- if (FState <> nil) then
- FreeMem(FState, sizeof(TSubKeyArray));
- inherited Destroy;
- end;
- {--------}
- procedure TaaDesEngine.ProcessBlock(const aSrc : TaaDesBlock;
- var aDest: TaaDesBlock);
- var
- Round : integer;
- Temp : longint;
- Block : packed record
- Left : longint;
- Right : longint;
- end;
- begin
- {perform the initial permutation of the source block}
- CalcPermutation(aSrc, Block, DesStartPerm, sizeof(DesStartPerm));
-
- {do the 16 rounds}
- for Round := 1 to 16 do begin
- Temp := Block.Right;
- Block.Right := Block.Left xor
- F(Block.Right, PSubKeyArray(FState)^[Round]);
- Block.Left := Temp;
- end;
-
- {this will have done one too many swaps of the right and
- left halves, so swap them back}
- Temp := Block.Right;
- Block.Right := Block.Left;
- Block.Left := Temp;
-
- {perform the final permutation of the source block}
- CalcPermutation(Block, aDest, DesFinalPerm, sizeof(DesFinalPerm));
- end;
- {--------}
- procedure TaaDesEngine.ProcessStream(aInStream : TStream;
- aOutStream : TStream;
- aMode : TaaDesMode);
- var
- i : integer;
- InSize : longint;
- BlockCount : integer;
- TotalBlockCount: integer;
- FullBlockCount : integer;
- BlocksToGo : integer;
- BytesRead : longint;
- LastBlock : TaaDesBlock;
- ThisBlock : TaaDesBlock;
- LastChunkIn : array [0..1] of TaaDesBlock;
- LastChunkOut : array [0..1] of TaaDesBlock;
- Buffer : array [0..127] of TaaDesBlock;
- begin
- {reposition the two streams}
- aInStream.Position := 0;
- aOutStream.Position := 0;
-
- {calculate the total number of blocks we shall be encoding, and
- the number of complete blocks}
- InSize := aInStream.Size;
- TotalBlockCount := (InSize + 7) div sizeof(TaaDesBlock);
- FullBlockCount := InSize div sizeof(TaaDesBlock);
-
- {prepare for CBC mode by setting the last block to binary zero}
- if (aMode = dmCBC) then
- FillChar(LastBlock, sizeof(LastBlock), 0);
-
- {if the total number of blocks equals the number of complete blocks,
- then all we need to do is to process them all: there is no partial
- block at the end to complicate things}
- if (FullBlockCount = TotalBlockCount) then begin
- BytesRead := aInStream.Read(Buffer, sizeof(Buffer));
- while (BytesRead <> 0) do begin
- BlockCount := BytesRead div sizeof(TaaDesBlock);
- {either: en/decryption with ECB mode...}
- if (aMode = dmECB) then begin
- for i := 0 to pred(BlockCount) do
- ProcessBlock(Buffer[i], Buffer[i]);
- end
- {or: encryption with CBC mode...}
- else if Encrypting then begin
- for i := 0 to pred(BlockCount) do begin
- XorDesBlock(LastBlock, Buffer[i]);
- ProcessBlock(Buffer[i], LastBlock);
- Buffer[i] := LastBlock;
- end
- end
- {otherwise: decryption with CBC mode...}
- else begin
- for i := 0 to pred(BlockCount) do begin
- ProcessBlock(Buffer[i], ThisBlock);
- XorDesBlock(LastBlock, ThisBlock);
- LastBlock := Buffer[i];
- Buffer[i] := ThisBlock;
- end
- end;
- aOutStream.WriteBuffer(Buffer, BytesRead);
- BytesRead := aInStream.Read(Buffer, sizeof(Buffer));
- end;
- end
-
- {otherwise we have a partial block at the end of the input stream}
- else begin
- {first process everything except the last full block and the
- final partial block}
- BlocksToGo := FullBlockCount - 1;
- while (BlocksToGo <> 0) do begin
- BlockCount := BlocksToGo;
- if (BlockCount > 128) then
- BlockCount := 128;
- aInStream.ReadBuffer(Buffer, BlockCount * sizeof(TaaDesBlock));
- {either: en/decryption with ECB mode...}
- if (aMode = dmECB) then begin
- for i := 0 to pred(BlockCount) do
- ProcessBlock(Buffer[i], Buffer[i]);
- end
- {or: encryption with CBC mode...}
- else if Encrypting then begin
- for i := 0 to pred(BlockCount) do begin
- XorDesBlock(LastBlock, Buffer[i]);
- ProcessBlock(Buffer[i], LastBlock);
- Buffer[i] := LastBlock;
- end
- end
- {otherwise: decryption with CBC mode...}
- else begin
- for i := 0 to pred(BlockCount) do begin
- ProcessBlock(Buffer[i], ThisBlock);
- XorDesBlock(LastBlock, ThisBlock);
- LastBlock := Buffer[i];
- Buffer[i] := ThisBlock;
- end
- end;
- aOutStream.WriteBuffer(Buffer, BlockCount * sizeof(TaaDesBlock));
- dec(BlocksToGo, BlockCount);
- end;
-
- {now read the final full and partial blocks
- (note that BytesRead will equal 9, 10, .., 15)}
- BytesRead := aInStream.Read(LastChunkIn, sizeof(LastChunkIn));
-
- {either: en/decryption with ECB mode...}
- if (aMode = dmECB) then begin
- {process the last full block}
- ProcessBlock(LastChunkIn[0], LastChunkOut[1]);
- {borrow enough bytes from the processed block to
- fill out the final partial block}
- for i := (BytesRead - 8) to 7 do
- LastChunkIn[1][i] := LastChunkOut[1][i];
- {process the filled block}
- ProcessBlock(LastChunkIn[1], LastChunkOut[0])
- end
-
- {or: encryption with CBC mode...}
- else if Encrypting then begin
- {process the last full block}
- XorDesBlock(LastBlock, LastChunkIn[0]);
- ProcessBlock(LastChunkIn[0], LastBlock);
- LastChunkOut[1] := LastBlock;
- {zero out the rest of the final partial block}
- for i := (BytesRead - 8) to 7 do
- LastChunkIn[1][i] := 0;
- {process the filled block}
- XorDesBlock(LastBlock, LastChunkIn[1]);
- ProcessBlock(LastChunkIn[1], LastChunkOut[0]);
- end
-
- {otherwise: decryption with CBC mode...}
- else begin
- {zero out the rest of the final partial block}
- for i := (BytesRead - 8) to 7 do
- LastChunkIn[1][i] := 0;
- {process the last full block}
- ProcessBlock(LastChunkIn[0], LastChunkOut[1]);
- XorDesBlock(LastChunkIn[1], LastChunkOut[1]);
- {borrow enough bytes from the processed block to
- fill out the final partial block}
- for i := (BytesRead - 8) to 7 do
- LastChunkIn[1][i] := LastChunkOut[1][i];
- {process the filled block}
- ProcessBlock(LastChunkIn[1], LastChunkOut[0]);
- XorDesBlock(LastBlock, LastChunkOut[0]);
- end;
-
- {write the final full and partial blocks}
- aOutStream.WriteBuffer(LastChunkOut, BytesRead);
- end;
- end;
- {====================================================================}
-
- end.
-